#ifndef _LINUX_DEVICE_MAPPER_H
#define _LINUX_DEVICE_MAPPER_H

#ifdef __KERNEL__

struct vd_target;
struct vd_table;
struct mapped_device;
struct target_dev;


typedef struct Target_Scsi_Cmnd_t {
    int a;
    void *device;
    int length;
    unsigned int  (* done)(struct Target_Scsi_Cmnd_t* cmd);
    void *private;
    
}Target_Scsi_Cmnd;

typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;

union map_info {
    void *ptr;
    unsigned long long ll;
};

/*
 * In the constructor the target parameter will already have the
 * table, type, begin and len fields filled in.
 */
typedef int (*vd_ctr_fn) (struct vd_target *target,
              unsigned int argc, char **argv);

/*
 * The destructor doesn't need to free the dm_target, just
 * anything hidden ti->private.
 */
typedef void (*vd_dtr_fn) (struct vd_target *ti);

/*
 * The map function must return:
 * < 0: error
 * = 0: The target will handle the io by resubmitting it later
 * > 0: simple remap complete
 */
typedef int (*vd_map_fn) (struct vd_target *ti, Target_Scsi_Cmnd *cmnd,
              union map_info *map_context);
typedef int (*vd_make_request)(struct vd_target *ti, Target_Scsi_Cmnd *cmnd, int rw);

typedef int (*vd_status_fn) (struct vd_target *ti, status_type_t status_type,
                 char *result, unsigned int maxlen);

struct target_type {
    const char *name;
    struct module *module;
    unsigned version[3];
    vd_ctr_fn ctr;
    vd_dtr_fn dtr;
    vd_map_fn map;
    vd_make_request make_request;
    vd_status_fn status;
};

struct io_restrictions {
    unsigned int        max_sectors;
    unsigned short        max_phys_segments;
    unsigned short        max_hw_segments;
    unsigned short        hardsect_size;
    unsigned int        max_segment_size;
    unsigned long        seg_boundary_mask;
    unsigned char        no_cluster; /* inverted so that 0 is default */
};

struct vd_target {
    struct vd_table *table;
    struct target_type *type;

    /* target limits */
    sector_t begin;
    sector_t len;

    /* FIXME: turn this into a mask, and merge with io_restrictions */
    /* Always a power of 2 */
    sector_t split_io;

    /*
     * These are automatically filled in by
     * dm_table_get_device.
     */
    struct io_restrictions limits;

    /* target specific data */
    void *private;

    /* Used to provide an error string from the ctr */
    char *error;
};

struct mapped_device *vd_get_md(unsigned int id);
void vd_get(struct mapped_device *md);
void vd_put(struct mapped_device *md);
int create_md(struct mapped_device **result);

void *vd_get_mdptr(struct mapped_device *md);
void vd_set_mdptr(struct mapped_device *md, void *ptr);

struct vd_table *vd_get_table(struct mapped_device *md);
void vd_table_get(struct vd_table *t);
void vd_table_put(struct vd_table *t);

int vd_lock_for_deletion(struct mapped_device *md);

int vd_table_add_target(struct vd_table *t, const char *type,
            sector_t start, sector_t len, char *params);
int vd_table_complete(struct vd_table *t);
int vd_table_create(struct vd_table **result, int mode,
            unsigned num_targets, struct mapped_device *md);

/*  vd.c */
const char *vd_device_name(struct mapped_device *md);

/* vd-target.c */
int vd_register_target(struct target_type *t);
int vd_unregister_target(struct target_type *t);

/* vd-table.c */
int vd_get_device(struct vd_target *ti, const char *path, sector_t start,
          sector_t len, int mode, struct target_dev **result);
void vd_put_device(struct target_dev *td);
int vd_table_get_mode(struct vd_table *t);

#endif    /* __KERNEL__ */
#endif    /* _LINUX_DEVICE_MAPPER_H */

